<?php
require_once("common.php");
require_once("Date.class.php");

// MySQL Data Types
define('SQLVAL_BIT', "bit");
define('SQLVAL_BOOLEAN', "boolean");
define('SQLVAL_DATE', "date");
define('SQLVAL_DATETIME', "datetime");
define('SQLVAL_NUMBER', "number");
define('SQLVAL_T_F', "t-f");
define('SQLVAL_TEXT', "text");
define('SQLVAL_TIME', "time");
define('SQLVAL_Y_N', "y-n");

function &createDriver($type) {
	$type = strtoupper($type);
	switch($type) {
		case "MYSQL":
			return new MySQLDriver();
		default:
			app_error("No driver for \"$type\" type of database");
	}
}

class DatabaseDriver {
	/* Database Methods */
	function connect($connectionString) {
		return false;
	}
	function selectDb($dbname, $con) {
		return false;
	}
	function close($con) {
		return false;
	}
	function query($con, $query) {
		return false;
	}
	function getError($con) {
		return false;
	}
	function getAffectedRows($con) {
		return false;
	}
	function getLastInsertId($con) {
		return false;
	}
	/* Result Methods */
	function getNumRows($result) {
		return false;
	}
	function getNumFields($result) {
		return false;
	}
	function getField($index, $result) {
		return false;
	}
	function nextRowAssoc($result) {
		return false;
	}
	function nextRowNum($result) {
		return false;
	}
	function freeResult($result) {
		return false;
	}
	
	/* Data Methods */
	/* Formats any value into a string suitable for SQL statements
	 * (NOTE: Also supports data types returned from the gettype function)
	 * $datatype Use SQLVALUE constants or the strings: string, text, varchar, char, boolean,
	 * bool, Y-N, T-F, bit, date, datetime, time, integer, int, number, double, float */
	function formatValue($value, $datatype, $con) {
		if(!isset($value) && is_null($value))
			return 'NULL';
			
		switch (strtolower(trim($datatype))) {
			case "text":
			case "string":
			case "varchar":
			case "char":
			case "s":
				return $this->formatString($value, $con);
			case "number":
			case "integer":
			case "int":
			case "double":
			case "float":
			case "i":
			case "n":
				return $this->formatNumber($value);
			case "boolean":  //boolean to use this with a bit field
			case "bool":
			case "bit":
			case "b":
				return $this->formatBoolean($value, "bit");
			case "y-n":  //boolean to use this with a char(1) field
				return $this->formatBoolean($value, "y-n");
			case "t-f":  //boolean to use this with a char(1) field
				return $this->formatBoolean($value, "t-f");
			case "date":
			case "d":
				return $this->formatDate($value);
			case "datetime":
			case "dt":
				return $this->formatDateTime($value);
			case "time":
			case "t":
				return $this->formatBoolean($value);
			default:
				app_error("DB: The value $value is not valid or datatype $datatype doesn't exists");
				return "NULL";
		}
	}
	
	function formatString($value, $con) {
		return "'". $str ."'";
	}
	
	function formatNumber($value) {
		if(isEmpty($value))
			return "NULL";
		if(is_numeric($value))
			return $value;
		app_error("DB: The value '$value' is not numeric");
		return "NULL";
	}
	
	function formatBoolean($value, $type = "bit") {
		switch($type) {
			case "bit":
				if ($this->_getBoolean($value))
				   return "1";
				return "0";
			case "y-n":  //boolean to use this with a char(1) field
				if ($this->_getBoolean($value))
					return "'Y'";
				return "'N'";
			case "t-f":  //boolean to use this with a char(1) field
				if ($this->_getBoolean($value))
					return "'T'";
				return "'F'";
		}
		app_error("DB: The boolean type $type is not valid");
		return "NULL";
	}
	
	/* Converts any value of any datatype into boolean (true or false) */
	function _getBoolean($value) {
		if (gettype($value) == "boolean") {
			if ($value == true)
				return true;
			return false;
		} elseif (is_numeric($value)) {
			if ($value > 0)
				return true;
			return false;
		}
		$cleaned = strtoupper(trim($value));
		if ($cleaned == "ON" || $cleaned == "SELECTED" || $cleaned == "CHECKED" ||
			$cleaned == "YES" || $cleaned == "Y" || $cleaned == "TRUE" || $cleaned == "T")
				return true;
		return false;
	}

	function formatDate($value) {
		if(empty($value))
			return "NULL";
		$date = new Date($value, 'd-m-y');
		if ($date->isValid()) {
			return "'" . $date->getDbDate() . "'";
		}
		app_error("DB: The value $value is not a valid date");
		return "NULL";
	}
	
	function formatTime($value) {
		if(empty($value))
			return "NULL";
		return "'" . date('H:i:s', strtotime($value)) . "'";
	}
	
	function formatDateTime($value) {
		// TODO implement datetime, time and timestamps the same as Date
		if(empty($value))
			return "NULL";
		if (self::_isDate($value)) {
			return "'" . date('Y-m-d H:i:s', strtotime($value)) . "'";
		}
		app_error("DB: The value $value is not a DateTime");
		return "NULL";
	}
}

class MySQLDriver extends DatabaseDriver {
	/* Database Methods */
	function connect($connectionString) {
		$params = explode(";", $connectionString);
		if(count($params) != 3) {
			app_error("Can't connect to database, invalid connection string");
			return false;
		}
		return mysql_connect($params[0], $params[1], $params[2]);
	}
	function selectDb($dbname, $con) {
		return mysql_select_db($dbname, $con);
	}
	function close($con) {
		mysql_close($con);
	}
	function query($con, $query) {
		return mysql_query($query, $con);
	}
	function getError($con) {
		if($con)
			return mysql_error($con);
		return mysql_error();
	}
	function getAffectedRows($con) {
		return mysql_affected_rows($con);
	}
	function getLastInsertId($con) {
		return mysql_insert_id($con);
	}
	/* Result Methods */
	function getNumRows($result) {
		return mysql_num_rows($result);
	}
	function getNumFields($result) {
		return mysql_num_fields($result);
	}
	function getField($index, $result) {
		return mysql_fetch_field($result, index);
	}
	function nextRowAssoc($result) {
		return mysql_fetch_array($result, MYSQL_ASSOC);
	}
	function nextRowNum($result) {
		return mysql_fetch_array($result, MYSQL_NUM);
	}
	function freeResult($result) {
		return mysql_free_result($result);
	}
	/* Data Methods */
	function formatString($value, $con) {
		return "'". mysql_real_escape_string($value, $con) ."'";
	}
}

?>